﻿using System;
using System.Linq;
using System.Windows.Input;
using Microsoft.Practices.Prism.Events;
using WhiteFlow.DevTrackingTool.UI.Events;
using WhiteFlow.DevTrackingTool.UI.Models;
using WhiteFlow.Wpf.Common.Commands;
using WhiteFlow.Wpf.Common.Mvvm.Model;
using WhiteFlow.Wpf.Common.Mvvm.ViewModel;

namespace WhiteFlow.DevTrackingTool.UI.ViewModels
{
    /// <summary>
    /// The ViewModel that manages and manipulates a worksheet.
    /// </summary>
    public class WorksheetViewModel : ViewModelBase
    {
        #region Constants

        /// <summary>
        /// The TasksListViewModel property name.
        /// </summary>
        public const string TasksListViewModelPropertyName = "TasksListViewModel";

        /// <summary>
        /// The ExpensesReportViewModel property name.
        /// </summary>
        public const string ExpensesReportViewModelPropertyName = "ExpensesReportViewModel";

        /// <summary>
        /// The CustomersListViewModel property name.
        /// </summary>
        public const string CustomersListViewModelPropertyName = "CustomersListViewModel";

        /// <summary>
        /// The ProjectsListViewModel property name.
        /// </summary>
        public const string ProjectsListViewModelPropertyName = "ProjectsListViewModel";

        /// <summary>
        /// The StatsViewModel property name.
        /// </summary>
        public const string StatsViewModelPropertyName = "StatsViewModel";

        /// <summary>
        /// The Worksheet property name.
        /// </summary>
        public const string WorksheetPropertyName = "Worksheet";

        /// <summary>
        /// The SelectedWorksheetTab property name.
        /// </summary>
        public const string SelectedWorksheetTabPropertyName = "SelectedWorksheetTab";

        /// <summary>
        /// The SelectedDay property name.
        /// </summary>
        public const string SelectedDayPropertyName = "SelectedDay";
        
        /// <summary>
        /// The SelectedTrackingDay property name.
        /// </summary>
        public const string SelectedTrackingDayPropertyName = "SelectedTrackingDay";

        #endregion

        #region Fields

        private TasksListViewModel tasksListViewModel;

        private ExpensesReportViewModel expensesReportViewModel;

        private CustomersListViewModel customersListViewModel;

        private ProjectsListViewModel projectsListViewModel;

        private StatsViewModel statsViewModel;

        private TrackingWorksheet worksheet;

        private int selectedWorksheetTab;

        private DateTime? selectedDay;

        private TrackingDay selectedTrackingDay;

        private ICommand selectPreviousDayCommand;

        private ICommand selectNextDayCommand;

        private SubscriptionToken worksheetChildChangedEventSubscriptionToken;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the ViewModel that manages the tasks list.
        /// </summary>
        /// <value>
        /// The ViewModel that manages the tasks list.
        /// </value>
        public TasksListViewModel TasksListViewModel
        {
            get
            {
                if (tasksListViewModel == null)
                    tasksListViewModel = new TasksListViewModel(this);

                return tasksListViewModel;
            }
            set
            {
                tasksListViewModel = value;
                OnPropertyChanged(TasksListViewModelPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the ViewModel that manages the expenses report.
        /// </summary>
        /// <value>
        /// The ViewModel that manages the expenses report.
        /// </value>
        public ExpensesReportViewModel ExpensesReportViewModel
        {
            get
            {
                if (expensesReportViewModel == null)
                    expensesReportViewModel = new ExpensesReportViewModel(this);

                return expensesReportViewModel;
            }
            set
            {
                expensesReportViewModel = value;
                OnPropertyChanged(ExpensesReportViewModelPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the ViewModel that manages the customers list.
        /// </summary>
        /// <value>
        /// The ViewModel that manages the customers list.
        /// </value>
        public CustomersListViewModel CustomersListViewModel
        {
            get
            {
                if (customersListViewModel == null)
                    customersListViewModel = new CustomersListViewModel(this);

                return customersListViewModel;
            }
            set
            {
                customersListViewModel = value;
                OnPropertyChanged(CustomersListViewModelPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the ViewModel that manages the projects list.
        /// </summary>
        /// <value>
        /// The ViewModel that manages the projects list.
        /// </value>
        public ProjectsListViewModel ProjectsListViewModel
        {
            get
            {
                if (projectsListViewModel == null)
                    projectsListViewModel = new ProjectsListViewModel(this);

                return projectsListViewModel;
            }
            set
            {
                projectsListViewModel = value;
                OnPropertyChanged(ProjectsListViewModelPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the ViewModel that manages the stats.
        /// </summary>
        /// <value>
        /// The ViewModel that manages the stats.
        /// </value>
        public StatsViewModel StatsViewModel
        {
            get
            {
                if (statsViewModel == null)
                    statsViewModel = new StatsViewModel(this);

                return statsViewModel;
            }
            set
            {
                statsViewModel = value;
                OnPropertyChanged(StatsViewModelPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the currently active worksheet.
        /// </summary>
        /// <value>
        /// The worksheet.
        /// </value>
        public TrackingWorksheet Worksheet
        {
            get
            {
                if (worksheet == null)
                    worksheet = new TrackingWorksheet();

                return worksheet;
            }
            set
            {
                if (value != worksheet)
                {
                    worksheet = value;
                    OnPropertyChanged(WorksheetPropertyName);
                }
            }
        }

        /// <summary>
        /// Gets or sets the selected tab in Worksheet view.
        /// </summary>
        /// <value>
        /// The selected tab in Worksheet view.
        /// </value>
        public int SelectedWorksheetTab
        {
            get { return selectedWorksheetTab; }
            set
            {
                selectedWorksheetTab = value;
                OnPropertyChanged(SelectedWorksheetTabPropertyName);
            }
        }

        /// <summary>
        /// Gets or sets the day selected from tracking calendar.
        /// </summary>
        /// <value>
        /// The selected day.
        /// </value>
        public DateTime SelectedDay
        {
            get
            {
                if (!selectedDay.HasValue)
                    selectedDay = DateTime.Now;

                return selectedDay.Value;
            }
            set
            {
                selectedDay = value;
                OnPropertyChanged(SelectedDayPropertyName);

                SelectedTrackingDay = Worksheet.Days.FirstOrDefault(d => d.CalendarDay.Date.Equals(value.Date));
            }
        }

        /// <summary>
        /// Gets or sets the selected tracking day.
        /// </summary>
        /// <value>
        /// The selected tracking day.
        /// </value>
        public TrackingDay SelectedTrackingDay
        {
            get { return selectedTrackingDay; }
            set
            {
                selectedTrackingDay = value;
                OnPropertyChanged(SelectedTrackingDayPropertyName);
            }
        }

        #endregion

        #region Commands

        /// <summary>
        /// Gets the command to select the previous day in calendar.
        /// </summary>
        public ICommand SelectPreviousDayCommand
        {
            get
            {
                if (selectPreviousDayCommand == null)
                    selectPreviousDayCommand = new DelegateCommand(SelectPreviousDay, delegate() { return true; });

                return selectPreviousDayCommand;
            }
        }

        /// <summary>
        /// Gets the command to select the next day in calendar.
        /// </summary>
        public ICommand SelectNextDayCommand
        {
            get
            {
                if (selectNextDayCommand == null)
                    selectNextDayCommand = new DelegateCommand(SelectNextDay, delegate() { return true; });

                return selectNextDayCommand;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WorksheetViewModel"/> class.
        /// </summary>
        public WorksheetViewModel()
        {
            worksheetChildChangedEventSubscriptionToken = App.EventAggregator.GetEvent<WorksheetItemChangedEvent>().Subscribe(SetWorksheetDirty);
        }

        #endregion

        #region Public Methods

        public void DeactivateWorksheetChangeNotification()
        {
            // Detach the PropertyModified event.
            if (worksheetChildChangedEventSubscriptionToken != null)
            {
                App.EventAggregator.GetEvent<WorksheetItemChangedEvent>().Unsubscribe(worksheetChildChangedEventSubscriptionToken);
            }
        }

        public void ActivateWorksheetChangeNotification()
        {
            // Attach the PropertyModified event.
            worksheetChildChangedEventSubscriptionToken = App.EventAggregator.GetEvent<WorksheetItemChangedEvent>().Subscribe(SetWorksheetDirty);
        }

        #endregion

        #region Commands Implementations

        private void SelectPreviousDay()
        {
            SelectedDay = SelectedDay.AddDays(-1);
        }

        private void SelectNextDay()
        {
            SelectedDay = SelectedDay.AddDays(1);
        }

        #endregion

        #region Event Handlers

        private void SetWorksheetDirty(NotifyPropertyChangedBase sender)
        {
            Worksheet.IsDirty = true;
        }

        #endregion
    }
}